package com.rui.memento.main;

import com.rui.memento.model.black.BlackGameRole;
import com.rui.memento.model.black.BlackRoleStateCaretaker;
import com.rui.memento.model.white.WhiteGameRole;
import com.rui.memento.model.white.WhiteRoleStateCaretaker;

/**
 * 备忘录模式（Memento Pattern）
 * <p>
 * <p>
 * 备忘录模式又称为快照模式（Snapshot Pattern）或令牌模式（Token Pattern），是指在不破坏封装的前提下，捕获一个对象的内部状态，并在对象之外保存这个状态，这样以后就可将该对象恢复到原先保存的状态。
 * <p>
 * 特征：“后悔药”
 * <p>
 * 备忘录模式的主要角色如下：
 * 发起人（Originator）角色：记录当前时刻的内部状态信息，提供创建备忘录和恢复备忘录数据的功能，实现其他业务功能，它可以访问备忘录里的所有信息。
 * 备忘录（Memento）角色：负责存储发起人的内部状态，在需要的时候提供这些内部状态给发起人。
 * 管理者（Caretaker）角色：对备忘录进行管理，提供保存与获取备忘录的功能，但其不能对备忘录的内容进行访问与修改。
 * <p>
 * 备忘录有两个等效的接口：
 * 窄接口：管理者(Caretaker)对象（和其他发起人对象之外的任何对象）看到的是备忘录的窄接口(narror Interface)，这个窄接口只允许他把备忘录对象传给其他的对象。
 * 宽接口：与管理者看到的窄接口相反，发起人对象可以看到一个宽接口(wide Interface)，这个宽接口允许它读取所有的数据，以便根据这些数据恢复这个发起人对象的内部状态。
 * <p>
 * <p>
 * 适用场景：
 * 需要保存历史快照的场景。
 * 希望在对象之外保存状态，且除了自己其他类对象无法访问状态保存具体内容。
 * <p>
 * 优点：
 * 简化发起人实体类职责，隔离状态存储与获取，实现了信息的封装，客户端无需关心状态的保存细节。
 * 提供状态回滚功能。
 * <p>
 * 缺点：
 * 消耗资源：如果需要保存的状态过多时，每一次保存都会消耗很多内存。
 *
 * @author ZhangRui
 * @date 2023/03/03 17:14
 **/
public class Main {

    public static void main(String[] args) {
        test1();

        test2();
    }

    /**
     * “白箱”备忘录模式
     * 备忘录角色对任何对象都提供一个宽接口，备忘录角色的内部所存储的状态就对所有对象公开。
     *
     * @param null
     * @return
     * @author ZhangRui
     * @date 2023/3/3 17:19
     */
    public static void test1() {

        System.out.println("===========打boss前状态===========");
        WhiteGameRole gameRole = new WhiteGameRole();
        gameRole.init();
        gameRole.showState();
        // 保存进度
        WhiteRoleStateCaretaker roleStateCaretaker = new WhiteRoleStateCaretaker();
        roleStateCaretaker.setRoleStateMemento(gameRole.saveState());
        System.out.println("===========打boss后状态===========");
        gameRole.fight();
        gameRole.showState();
        System.out.println("===========恢复状态===========");
        gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());
        gameRole.showState();
        // ===========打boss前状态===========
        // 角色生命力:100
        // 角色攻击力:100
        // 角色防御力:100
        // ===========打boss后状态===========
        // 角色生命力:0
        // 角色攻击力:0
        // 角色防御力:0
        // ===========恢复状态===========
        // 角色生命力:100
        // 角色攻击力:100
        // 角色防御力:100
    }

    /**
     * “黑箱”备忘录模式
     * 备忘录角色对发起人对象提供了一个宽接口，而为其他对象提供一个窄接口，在Java语言中，
     * 实现双重接口的办法就是将备忘录类设计成发起人类的内部成员类。
     * <p>
     * <p>
     * 将RoleStateMemento设为GameRole的内部类，从而将RoleStateMemento对象封装在GameRole 里面；
     * 在外面提供一个标识接口Memento给RoleStateCaretaker及其他对象使用。
     * 这样GameRole类看到的是RoleStateMemento所有的接口，而RoleStateCaretaker及其他对象看到的仅仅是标识接口Memento所暴露出来的接口，
     * 从而维护了封装型。
     *
     * @param null
     * @return
     * @author ZhangRui
     * @date 2023/3/3 17:25
     */
    public static void test2() {

        System.out.println("===========打boss前状态===========");
        BlackGameRole gameRole = new BlackGameRole();
        gameRole.init();
        gameRole.showState();
        // 保存进度
        BlackRoleStateCaretaker roleStateCaretaker = new BlackRoleStateCaretaker();
        roleStateCaretaker.setMemento(gameRole.saveState());
        System.out.println("===========打boss后状态===========");
        gameRole.fight();
        gameRole.showState();
        System.out.println("===========恢复状态===========");
        gameRole.recoverState(roleStateCaretaker.getMemento());
        gameRole.showState();
        // ===========打boss前状态===========
        // 角色生命力:100
        // 角色攻击力:100
        // 角色防御力:100
        // ===========打boss后状态===========
        // 角色生命力:0
        // 角色攻击力:0
        // 角色防御力:0
        // ===========恢复状态===========
        // 角色生命力:100
        // 角色攻击力:100
        // 角色防御力:100
    }
}
